﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using YArchitech.LIB;

namespace YArchitech.Controls
{
	[DesignerCategory("Code")]
	public class ThreeStateTreeview : TreeView
	{
		public ThreeStateTreeview(bool ifWhiteBackColor = false)
		{
			this.m_bIfWhiteBackColor = ifWhiteBackColor;
			this.InitializeComponent();
			base.DrawMode = TreeViewDrawMode.OwnerDrawAll;
			this._imgIndeterminate = this.imageList1.Images[2];
			base.StateImageList = this.imageList1;
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing && this._graphics != null)
			{
				this._graphics.Dispose();
				this._graphics = null;
				if (this.components != null)
				{
					this.components.Dispose();
				}
			}
			base.Dispose(disposing);
		}

		protected override void OnHandleCreated(EventArgs e)
		{
			base.OnHandleCreated(e);
			this._graphics = base.CreateGraphics();
		}

		protected override void OnSizeChanged(EventArgs e)
		{
			base.OnSizeChanged(e);
			if (this._graphics != null)
			{
				this._graphics.Dispose();
				this._graphics = base.CreateGraphics();
			}
		}

		protected override void OnBeforeCheck(TreeViewCancelEventArgs e)
		{
			if (this._skipCheckEvents)
			{
				return;
			}
			base.OnBeforeCheck(e);
		}

		protected override void OnAfterCheck(TreeViewEventArgs e)
		{
			if (this._skipCheckEvents)
			{
				return;
			}
			this._skipCheckEvents = true;
			try
			{
				TreeNode treeNode = e.Node;
				int state = (Math.Max(0, treeNode.StateImageIndex) == 1) ? 0 : 1;
				if (state == 1 == treeNode.Checked)
				{
					this.InheritCheckstate(treeNode, state);
					for (treeNode = treeNode.Parent; treeNode != null; treeNode = treeNode.Parent)
					{
						if (state != 2 && treeNode.Nodes.Cast<TreeNode>().Any((TreeNode ndChild) => ndChild.StateImageIndex != state))
						{
							state = 2;
						}
						this.AssignState(treeNode, state);
					}
					base.OnAfterCheck(e);
				}
			}
			finally
			{
				this._skipCheckEvents = false;
			}
		}

		private void AssignState(TreeNode nd, int state)
		{
			bool flag = state == 1;
			bool flag2 = nd.StateImageIndex != state;
			if (flag2)
			{
				nd.StateImageIndex = state;
			}
			if (nd.Checked != flag)
			{
				nd.Checked = flag;
				return;
			}
			if (flag2)
			{
				base.Invalidate(this.GetCheckRect(nd));
			}
		}

		public void SetCheckStatus(TreeNode nd, bool bChecked = true)
		{
			if (!base.CheckBoxes)
			{
				return;
			}
			int state = 0;
			if (bChecked)
			{
				state = 1;
			}
			this.InheritCheckstate(nd, state);
			for (nd = nd.Parent; nd != null; nd = nd.Parent)
			{
				if (state != 2 && nd.Nodes.Cast<TreeNode>().Any((TreeNode ndChild) => ndChild.StateImageIndex != state))
				{
					state = 2;
				}
				this.AssignState(nd, state);
			}
		}

		private void InheritCheckstate(TreeNode nd, int state)
		{
			this.AssignState(nd, state);
			foreach (object obj in nd.Nodes)
			{
				TreeNode nd2 = (TreeNode)obj;
				this.InheritCheckstate(nd2, state);
			}
		}

		public CheckState GetNodeCheckState(TreeNode nd)
		{
			return (CheckState)Math.Max(0, nd.StateImageIndex);
		}

		protected override void OnDrawNode(DrawTreeNodeEventArgs e)
		{
			if (e.Node.StateImageIndex == 2)
			{
				this._indeterminateds.Add(e.Node);
			}
			e.DrawDefault = true;
			base.OnDrawNode(e);
		}

		protected override void WndProc(ref Message m)
		{
			if (m.Msg == 515)
			{
				Point pt = base.PointToClient(Control.MousePosition);
				if (base.HitTest(pt).Location == TreeViewHitTestLocations.StateImage)
				{
					return;
				}
			}
			base.WndProc(ref m);
			if (m.Msg == 15)
			{
				foreach (TreeNode nd in this._indeterminateds)
				{
					this._graphics.DrawImage(this._imgIndeterminate, this.GetCheckRect(nd).Location);
				}
				this._indeterminateds.Clear();
			}
		}

		private Rectangle GetCheckRect(TreeNode nd)
		{
			Point location = nd.Bounds.Location;
			location.X -= ((base.ImageList == null) ? 16 : 35);
			return new Rectangle(location.X, location.Y, 16, 16);
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public new ImageList StateImageList
		{
			get
			{
				return base.StateImageList;
			}
			set
			{
			}
		}

		private void InitializeComponent()
		{
			this.components = new Container();
			new ComponentResourceManager(typeof(ThreeStateTreeview));
			base.SuspendLayout();
			this.imageList1 = new ImageList();
			this.imageList1.ImageSize = new Size(16, 16);
			this.imageList1.Images.Add(Resources.UnChecked);
			if (this.m_bIfWhiteBackColor)
			{
				this.imageList1.Images.Add(Resources.WhiteChecked);
			}
			else
			{
				this.imageList1.Images.Add(Resources.Checked);
			}
			this.imageList1.Images.Add(Resources.Indeterminated);
			base.LineColor = Color.Black;
			base.ResumeLayout(false);
		}

		private ImageList imageList1;

		private IContainer components;

		private List<TreeNode> _indeterminateds = new List<TreeNode>();

		private Graphics _graphics;

		private Image _imgIndeterminate;

		private bool _skipCheckEvents;

		private bool m_bIfWhiteBackColor;
	}
}
